﻿using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management.Instrumentation;

namespace ScarecrowLibrary
{
    public static class scEnvironment
    {
        /// <summary>
        /// Ottiene la versione dell'applicazione in esecuzione.
        /// (Solo se è una distribuzione ClickOnce)
        /// </summary>
        public static string ApplicationVersion
        {
            get
            {
                //Se l'applicazione corrente è una distribuzione ClickOnce
                if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed)
                {
                    //Determino i dati di distribuzione
                    System.Deployment.Application.ApplicationDeployment ad = System.Deployment.Application.ApplicationDeployment.CurrentDeployment;
                    //Determino la versione corrente e la restituisco sotto forma di stringa
                    return ad.CurrentVersion.ToString();
                }
                //Se arrivo qui vuol dire che non è una distribuzione ClickOnce
                //Restituisco un valore negativo
                return "V: -1.0.0.0";
            }
        }
        /// <summary>
        /// Ottiene la quantità di RAM installata sul computer.
        /// </summary>
        public static ulong TotalPhysicalMemory
        {
            //Mi appoggio alle librerie VB.Net
            get { return new Microsoft.VisualBasic.Devices.ComputerInfo().TotalPhysicalMemory; }
        }
        /// <summary>
        /// Ottiene la quantità di memoria virtuale totale disponibile sul computer.
        /// </summary>
        public static ulong TotalVirtualMemory
        {
            //Mi appoggio alle librerie VB.Net
            get { return new Microsoft.VisualBasic.Devices.ComputerInfo().TotalVirtualMemory; }
        }
        /// <summary>
        /// Ottiene la quantità di memoria fisica libera sul computer.
        /// </summary>
        public static ulong AvaiablePhysicalMemory
        {
            //Mi appoggio alle librerie VB.Net
            get { return new Microsoft.VisualBasic.Devices.ComputerInfo().AvailablePhysicalMemory; }
        }
        /// <summary>
        /// Ottiene la quantità di memoria virtuale libera sul computer.
        /// </summary>
        public static ulong AvaiableVirtualMemory
        {
            //Mi appoggio alle librerie VB.Net
            get { return new Microsoft.VisualBasic.Devices.ComputerInfo().AvailableVirtualMemory; }
        }
        /// <summary>
        /// True se il processo in esecuzione è a 64bit, False altrimenti.
        /// </summary>
        public static bool Is64BitProcess
        {
            //Se il processo attuale è a 64bit il puntatore avrà dimensione 8 byte
            get { return IntPtr.Size == 8; }
        }
        /// <summary>
        /// True se il Sistema Operativo in esecuzione è a 64bit, False altrimenti.
        /// </summary>
        public static bool Is64BitOperatingSystem
        {
            get
            {
                // Ovviamente se il processo è a 64bit, anche il sistema lo sarà!
                if (Is64BitProcess)
                    return true;
                // Se arrivo qui vuol dire che il processo gira a 32 bit.
                // Sono necessariamente un sistema a 32bit?
                // Se stò girando all'interno di WoW64, allora il sistema è a 64bit!
                
                bool isWow64;
                // Controllo che il kernel contenga la funzione IsWow64Process
                // Richiamo la funzione e restituisco un booleano come risultato (isWow64)
                // se isWow64 == true, allora tutto è true.
                return ModuleContainsFunction("kernel32.dll", "IsWow64Process") && IsWow64Process(GetCurrentProcess(), out isWow64) && isWow64;
            }
        }
        /// <summary>
        /// Ottiene il nome completo del Sistema Operativo in uso.
        /// </summary>
        public static string OSName
        {
            //Mi appoggio alle librerie VB.Net
            get { return new Microsoft.VisualBasic.Devices.ComputerInfo().OSFullName; }
        }
        /// <summary>
        /// Ottiene la versione del Sistema Operativo corrente.
        /// </summary>
        public static string OSVersion
        {
            get { return Environment.OSVersion.Version.ToString(); }
        }
        /// <summary>
        /// Ottiene la versione del Service Pack corrente.
        /// </summary>
        public static string OSServicePack
        {
            get { return Environment.OSVersion.ServicePack; }
        }
        /// <summary>
        /// Ottiene una stringa composta dalla versione completa del Sistema Operativo.
        /// </summary>
        public static string OSFullVersion
        {
            get { return Environment.OSVersion.VersionString; }
        }
        /// <summary>
        /// Ottiene l'ID della piattaforma in uso.
        /// </summary>
        public static string OSPlatform
        {
            get { return Environment.OSVersion.Platform.ToString(); }
        }

        /// <summary>
        /// Verifico che il modulo invocato contenga la funzione specificata.
        /// </summary>
        /// <param name="moduleName">Modulo da verificare.</param>
        /// <param name="methodName">Funzione da verificare</param>
        /// <returns>Restituisce un valore che indica se la funzione è contenuta o no nel modulo.</returns>
        static bool ModuleContainsFunction(string moduleName, string methodName)
        {
            IntPtr hModule = GetModuleHandle(moduleName);
            if (hModule != IntPtr.Zero)
                return GetProcAddress(hModule, methodName) != IntPtr.Zero;
            return false;
        }

        //DLL Import per la P/Invoke
        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        extern static bool IsWow64Process(IntPtr hProcess, [MarshalAs(UnmanagedType.Bool)] out bool isWow64);
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        extern static IntPtr GetCurrentProcess();
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        extern static IntPtr GetModuleHandle(string moduleName);
        [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
        extern static IntPtr GetProcAddress(IntPtr hModule, string methodName);
    }
}
